package br.ufes.ceunes.poo.model.pojo;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

/**
 * Classe para objetos do tipo Produto, onde serão contidos, valores,
 * identificadores e métodos para o mesmo.
 */
@Entity
@Table(name = "produto")
public class Produto implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;
    
    @Column
    private String nome;
    
    @Column
    protected Double preco;
    
    @Column
    private Integer quantidadeEstoque;
    
    @ManyToMany(mappedBy = "produtos")
    private List<Fornecedor> fornecedor;

    /**
     * Contrutor que instancia a lista de fornecedores do Produto
     */
    public Produto() {
        fornecedor = new ArrayList<>();
    }

    /**
     * Construtor do Produto
     *
     * Reaproveita o construtor
     *
     * @param nome - atribui o nome ao Produto
     */
    public Produto(String nome) {
        this();
        this.nome = nome;
        this.preco = 0.0;
        this.quantidadeEstoque = 0;
    }

    /**
     * Construtor do produto
     *
     * Reaproveita o construtor
     *
     * @param nome - atribui nome ao Produto
     * @param preco - atribui valor ao Produto
     */
    public Produto(String nome, Double preco) {
        this(nome);
        if (this.preco < 0) {
            this.preco = 0.0;
        }
        this.preco = preco;
    }

    /**
     * Construtor do Produto
     *
     * Reaproveita o construtor
     *
     * @param nome - atribui nome ao Produto
     * @param preco - atribui preço ao Produto
     * @param quantidade - atribui quantidade ao Produto
     */
    public Produto(String nome, Double preco, Integer quantidade) {
        this(nome, preco);
        if (quantidade < 0) {
            this.quantidadeEstoque = 0;
        }
        this.quantidadeEstoque = quantidade;
    }

    /**
     * Método para retornar o preço do Produto
     *
     * @return Double - preço - valor do Produto
     */
    public Double getPreco() {
        return this.preco;
    }

    /**
     * Mátodo para retorna a quantidade de Produto no estoque
     *
     * @return Integer - quantidadeEstoque - quantidade em estoque
     */
    public Integer getEstoque() {
        return this.quantidadeEstoque;
    }

    /**
     * Método para retornar o nome do Produto
     *
     * @return String - nome - nome do Produto
     */
    public String getNome() {
        return this.nome;
    }

    /**
     * Método para alterar o nome do Produto
     *
     * @param novoNome - nome atribuido ao Produto
     */
    public void setNome(String novoNome) {
        this.nome = novoNome;
    }

    /**
     * Método para alterar o preço do Produto
     *
     * @param novoPreco - preço atribuido ao Produto
     */
    public void setPreco(Double novoPreco) {
        this.preco = novoPreco;
    }

    /**
     * Método para alterar o preço do Produto
     *
     * @param novoPreco - preço atribuido ao Produto
     */
    public void alterarPreco(Double novoPreco) {
        if (novoPreco > 0) {
            this.preco = novoPreco;
        }
    }

    /**
     * Método para retornar o ID do produto
     *
     * @return Indteger - id - identificador do Produto
     */
    public Integer getId() {
        return id;
    }

    /**
     * Método para alterar o ID do Produto
     *
     * @param id - identificador do Produto
     */
    public void setId(int id) {
        if (this.id == null) {
            this.id = id;
        }
    }

    /**
     * Método para retornar a lista de fornecedores do Produto
     *
     * @return List - lista dos fornecedores
     */
    public List<Fornecedor> getFornecedor() {
        return Collections.unmodifiableList(fornecedor);
    }

    /**
     * Método para adicionar um fornecedor na lista de fornecedores
     *
     * @param f - fornecedor que será adicionado na lista
     */
    public void adicionaFornecedor(Fornecedor f) {
        this.fornecedor.add(f);
    }

    /**
     * Método para retornar a quantidade de fornecedores do Produto
     *
     * @return Integer - quantidade de fornecedores
     */
    public Integer getNumeroFornecedores() {
        return fornecedor.size();
    }

    /**
     * Método para retornar a lista de fornecedores do Produto
     *
     * @return List - fornecedor - lista de fornecedores
     */
    public List<Fornecedor> getFornecedores() {
        return this.fornecedor;
    }

    /**
     * Método para aumentar a qauntidade de Produto no estoque
     *
     * @param incremento - quantidade a ser acrescentada
     */
    public void aumentarEstoque(Integer incremento) {
        if (incremento >= 0) {
            this.quantidadeEstoque += incremento;
        }
    }

    /**
     * Método para reduzir a quantidade de Produto no estoque
     *
     * @param decremento - quantidade a ser decrementada
     */
    public void reduzirEstoque(Integer decremento) {
        if (decremento >= 0) {
            this.quantidadeEstoque -= decremento;
        }
    }

    /**
     * Sobrescrição do método hashCode para agilizar a busca em collections
     *
     * @return hash - O método retorna um código hash de um objeto
     */
    @Override
    public int hashCode() {
        int hash = 7;
        hash = 67 * hash + Objects.hashCode(this.id);
        return hash;
    }

    /**
     * Sobrescrição do método equals
     *
     * @param obj - objeto para comparação
     * @return boolean - false se não encontra, true caso contrário
     */
    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Produto other = (Produto) obj;
        if (!Objects.equals(this.id, other.id)) {
            return false;
        }
        return true;
    }

    /**
     * Método para imprimir os dados do Produto
     */
    public void imprimeDados() {
        System.out.println("ID :" + this.id + "\t" + "Nome :" + this.nome);
    }

}
